#pragma once

#include <linux/kconfig.h>
#include <linux/errno.h>
#include <linux/sched/task_types.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/smp_types.h>

struct task_struct;

typedef void (*smp_call_func_t)(void *info);
typedef bool (*smp_cond_func_t)(int cpu, void *info);

/*
 * structure shares (partial) layout with struct irq_work
 */
struct __call_single_data
{
    struct __call_single_node node;
    smp_call_func_t func;
    void *info;
};

/* Use __aligned() to avoid to use 2 cache lines for 1 csd */
typedef struct __call_single_data call_single_data_t __aligned(sizeof(struct __call_single_data));

void smp_setup_processor_id(void);
extern int __cpu_up(unsigned int cpu, struct task_struct *tidle);

#ifdef CONFIG_SMP
#include <asm/smp.h>

void smp_init(void);

extern unsigned int setup_max_cpus;

/*
 * Prepare machine for booting other CPUs.
 */
extern void smp_prepare_cpus(unsigned int max_cpus);

#else /* !smp */
#define raw_smp_processor_id() 0

static inline void smp_init(void) {}

#define setup_max_cpus 0

#define smp_prepare_cpus(x)
#endif

/*
 * Allow the architecture to differentiate between a stable and unstable read.
 * For example, x86 uses an IRQ-safe asm-volatile read for the unstable but a
 * regular asm read for the stable.
 */
#ifndef __smp_processor_id
#define __smp_processor_id() raw_smp_processor_id()
#endif

#define smp_processor_id() __smp_processor_id()

int smp_call_function_single_async(int cpu, call_single_data_t *csd);
